#pragma once
#include <pthread.h>
#include <queue>
#include <unistd.h>
#include <string>
#include "task.hpp"
#define gnum  5
template<typename T>
class BlockQueue
{
public:
    BlockQueue(int max = gnum):max_(max)
    {
        pthread_mutex_init(&lock_, nullptr);
        pthread_cond_init(&c_cond_, nullptr);
        pthread_cond_init(&p_cond_, nullptr);
        low_ = max_ / 3;
        high_ = max_ * 2 / 3;
    }

    void push(const T& t)
    {
        pthread_mutex_lock(&lock_);

        //循环，避免伪唤醒
        while(queue_.size() == max_)
        {
            pthread_cond_wait(&p_cond_, &lock_);
        }

        queue_.push(t);
        
        if(queue_.size() >= high_)
        {
            pthread_cond_signal(&c_cond_);
        }

        pthread_mutex_unlock(&lock_);

    }

    T pop()
    {
        pthread_mutex_lock(&lock_);

        //循环，避免伪唤醒
        while(queue_.size() == 0)
        {
            pthread_cond_wait(&c_cond_, &lock_);
        }

        T ret = queue_.front();
        queue_.pop();
        if(queue_.size() <= low_)
        {
            pthread_cond_signal(&p_cond_);
        }

        pthread_mutex_unlock(&lock_);
        return ret;
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&lock_);
        pthread_cond_destroy(&c_cond_);
        pthread_cond_destroy(&p_cond_);

    }
private:
    std::queue<T> queue_;
    pthread_mutex_t lock_;
    pthread_cond_t c_cond_;
    pthread_cond_t p_cond_;
    int max_; 
    int low_; //低水位
    int high_;//高水位
};